package com._public
{
	import flash.utils.ByteArray;
	import flash.utils.getQualifiedClassName;
	import flash.xml.XMLNode;

	/**
	 * ...
	 * @author Johnny Cheng
	 */
	public class ObjectUtil 
	{
		/**
		 * 复制基本对象
		 * @param	value
		 * @return
		 */
		static public function copy(value:Object):Object
		{
			var ba:ByteArray = new ByteArray();
			ba.writeObject(value);
			ba.position = 0;
			return ba.readObject();
		}
		
		/**
		 * 深度复制，可复制任何对象
		 * @param	value
		 * @param	...args 构造函数参数
		 * @return
		 */
		static public function clone(value:Object, ...args):Object
		{
			var C:Class = value.constructor;
			switch(args.length) {
				case 0: return new C();
				case 1: return new C(args[0]);
				case 2: return new C(args[0], args[1]);
				case 3: return new C(args[0], args[1], args[2]);
				case 4: return new C(args[0], args[1], args[2], args[3]);
				case 5: return new C(args[0], args[1], args[2], args[3], args[4]);
				case 6: return new C(args[0], args[1], args[2], args[3], args[4], args[5]);
				case 7: return new C(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
				case 8: return new C(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]);
				case 9: return new C(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]);
				case 10: return new C(args[0], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9]);
				case 11: return new C(args[0], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10]);
				case 12: return new C(args[0], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11]);
				case 13: return new C(args[0], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12]);
				case 14: return new C(args[0], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13]);
				case 15: return new C(args[0], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14]);
				case 16: return new C(args[0], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14], args[15]);
				case 17: return new C(args[0], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14], args[15], args[16]);
				case 18: return new C(args[0], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14], args[15], args[16], args[17]);
			}
			return null;
		}
		
		static public function isSimple(value:Object):Boolean
		{
			var type:String = typeof(value);
			switch (type) {
				case "number":
				case "string":
				case "boolean":
				{
					return true;
				}

				case "object":
				{
					return (value is Date) || (value is Array);
				}
			}
			return false;
		}
		
		static public function isVerySimple(value:Object):Boolean
		{
			var type:String = typeof(value);
			return type == "boolean" || type == "number" || type == "string";
		}
		
		static public function getKeys(obj:Object):Array
		{
			var arr:Array = [];
			for (var key:* in obj) {
				arr.push(key);
			}
			return arr;
		}
		
		static public function getValues(obj:Object):Array
		{
			var arr:Array = [];
			for each (var value:* in obj) {
				arr.push(value);
			}
			return arr;
		}
		
		static public function getSubObject(source:Object, property:*, value:*):*
		{
			for each(var obj:* in source) {
				if (obj[property] == value) {
					return obj;
				}
			}
			return null;
		}
		
		static public function toBinary(value:Object):ByteArray
		{
			var buffer:ByteArray = new ByteArray();
			buffer.writeObject(value);
			buffer.compress();
			return buffer;
		}
		
		static public function toObject(value:ByteArray):Object
		{
			value.uncompress();
			return value.readObject();
		}
		
		static public function toString(value:Object):String
		{
			if (!isSimple(value) || value is Array) {
				return internalToString(value);
			}
			return value.toString();
		}
		
		static private function internalToString(value:Object, index:int = 0):String
		{
			var space:String = "";
			for (var i:int = 0; i < index; i++) {
				space += "   ";
			}
			var str:String = "";
			var type:String = value == null ? "null" : typeof(value);
			switch (type) {
			case "boolean":
			case "number":
			case "string":
				return value.toString();
			case "object":
			{
				if (value is Date) return value.toString();
				else if (value is XMLNode) return value.toString();
				else if (value is Class) return "(" + getQualifiedClassName(value) + ")";
				else
				{
					str += "#" + ((value is Array) ? "Array" : "Object") + "\n";
					for (var s:* in value) {
						str += space + s + "->" + internalToString(value[s], index + 1) + "\n";
					}
					return str.slice(0, str.length - 1);
				}
				break;
            }
			case "xml":
				return value.toXMLString();
            default:
				return "(" + type + ")";
			}
			return "(unknown)";
		}
	}

}